package analiseSintatica.Regras.Tipos;

import java.util.LinkedList;

import AnaliseLexicaFinal.EstruturaDeDados.LinkToken;
import analiseSintatica.ErroSintaticoException;
import analiseSintatica.Regras.Regra;
import analiseSintatica.estruturadados.ErroSintatico;
import analiseSintatica.estruturadados.NoArvore;

/**
 *
 * @author Ivo Romário
 */

public class RegraTipo  extends Regra{



    protected static Regra instancia;

    protected String estrutura = "<tipo_primitivo> |  identificador | void";

    
    /**
     * Construtor privado necessario ao singleton
     */
    private RegraTipo() {
    }

    /**
     * Retorna a unica instancia dessa classe.
     * @return
     */
    public static RegraTipo getInstance() {
        if (instancia == null) {
            instancia = new RegraTipo();
        }
        return (RegraTipo) instancia;
    }

    
    @Override
    public NoArvore analisar(LinkedList<LinkToken> listaTokens) throws ErroSintaticoException {

         ErroSintaticoException erros = new ErroSintaticoException();

         NoArvore naoTerminalTipo = new NoArvore("<tipo>", false);

         if(RegraTipoPrimitivo.getInstance().getPrimeiro().contains(listaTokens.getFirst().getLexema())){
             try{
                 naoTerminalTipo.adicionaFilho(RegraTipoPrimitivo.getInstance().analisar(listaTokens));
             }
             catch(ErroSintaticoException e){
                while (e.size() != 0) {
                    erros.addErros(e.getErros());
                }
             }
         }
         else if (listaTokens.getFirst().getToken().equals("identificador")){
             naoTerminalTipo.adicionaFilho(reconheceToken(listaTokens, "identificador",estrutura));
         }
         else{
             try{
                 naoTerminalTipo.adicionaFilho(reconheceToken(listaTokens, "void",estrutura));
             }
             catch(ErroSintaticoException e){
                ErroSintatico erro = e.getErros();
                erro.setCorreto(estrutura);
                erros.addErros(erro);
                LinkedList<String> sincronizacao = RegraTipo.getInstance().getSeguinte();
                LinkedList<String> id_void = new LinkedList<String>();
                id_void.add("void");
                sincronizacao = getUniao(sincronizacao, id_void);
                while (!listaContem(sincronizacao, listaTokens.getFirst())) {
                    erros.addErros("Token " + listaTokens.getFirst().getToken() + " nao permitido", estrutura, listaTokens.getFirst().getLinha());
                    listaTokens.removeFirst();
                }
                if (listaTokens.getFirst().getToken().equals("void")) {
                    listaTokens.removeFirst();
                }
             }
         }

         if(erros.size() != 0){
          throw erros;
         }
         System.out.println("Terminei Regra Tipo");
         return naoTerminalTipo;
    }

    

    @Override
    protected void setPrimeiro() {
        primeiro=RegraTipoPrimitivo.getInstance().getPrimeiro();
        primeiro.add("identificador");
        primeiro.add("void");
    }

    @Override
    protected void setSeguinte() {
        seguinte.add("identificador");
    }

}

